package sdk

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/client/httplib"
	"github.com/beego/beego/v2/core/logs"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
)

type ImageInfo struct {
	Size       int64  `json:"size"`
	FileName   string `json:"fileName"`
	Scene      string `json:"scene"`
	Suffix     string `json:"suffix"`
	Md5        string `json:"md5"`
	CreateTime int64  `json:"createTime"`
	UpdateTime int64  `json:"updateTime"`
}

type ImagesBedClient struct {
	Protocol  string
	Host      string
	Port      int
	Prefix    string
	FileField string
}

// NewImagesBedClient 初始化客户端
func NewImagesBedClient(protocol string, host string, port int) *ImagesBedClient {
	return &ImagesBedClient{
		Protocol:  protocol,
		Host:      host,
		Port:      port,
		Prefix:    "v1",
		FileField: "image",
	}
}

func (ibc *ImagesBedClient) BuildURL(uri string) string {
	return fmt.Sprintf("%s://%s:%d/%s/%s", ibc.Protocol, ibc.Host, ibc.Port, ibc.Prefix, uri)
}

// CreateScene 创建场景
func (ibc *ImagesBedClient) CreateScene(name string) bool {
	req := httplib.Post(ibc.BuildURL("scene/" + name))
	if resp, err := req.DoRequest(); err == nil {
		if resp.StatusCode == http.StatusOK {
			return true
		}
	}
	return false
}

// DeleteScene 删除场景
func (ibc *ImagesBedClient) DeleteScene(name string) bool {
	req := httplib.Delete(ibc.BuildURL("scene/" + name))
	if resp, err := req.DoRequest(); err == nil {
		if resp.StatusCode == http.StatusOK {
			return true
		}
	}
	return false
}

// GetScene 获取所有场景
func (ibc *ImagesBedClient) GetScene() ([]string, error) {
	req := httplib.Get(ibc.BuildURL("scene"))
	if resp, err := req.DoRequest(); err == nil {
		if resp.StatusCode == http.StatusOK {
			names := make([]string, 0)
			bytes, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return nil, err
			}

			err1 := json.Unmarshal(bytes, &names)
			if err1 != nil {
				return nil, err1
			}
			return names, nil
		} else {
			return nil, errors.New("net error")
		}
	} else {
		return nil, err
	}
}

// Upload 上传文件
func (ibc *ImagesBedClient) Upload(scene string, filename string) (string, error) {
	req := httplib.Post(ibc.BuildURL("push/" + scene + "?field=" + ibc.FileField))
	req.PostFile(ibc.FileField, filename)
	if resp, err := req.DoRequest(); err == nil {
		bytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return "", err
		}
		if resp.StatusCode == http.StatusOK {
			return strings.ReplaceAll(string(bytes), "\"", ""), nil
		} else {
			return "", errors.New(string(bytes))
		}
	} else {
		return "", err
	}
}

// DeleteImage 删除图片
func (ibc *ImagesBedClient) DeleteImage(md5 string) bool {
	req := httplib.Delete(ibc.BuildURL("delete/" + md5))
	if resp, err := req.DoRequest(); err == nil {
		if resp.StatusCode == http.StatusOK {
			return true
		}
	}
	return false
}

// GetViewURL 获取预览链接，支持压缩，compress 0-100
func (ibc *ImagesBedClient) GetViewURL(md5 string, compress int) string {
	return ibc.BuildURL("view/" + md5 + "?compress=" + fmt.Sprintf("%d", compress))
}

// GetImageInfo 获取图片信息
func (ibc ImagesBedClient) GetImageInfo(md5 string) *ImageInfo {
	info := new(ImageInfo)
	err := httplib.Get(ibc.BuildURL("info/" + md5)).ToJSON(info)
	if err == nil {
		return info
	}
	return nil
}

// GetDownloadURL 获取下载链接，支持断点下载
func (ibc *ImagesBedClient) GetDownloadURL(md5 string) string {
	return ibc.BuildURL("download/" + md5)
}

// Reader 获取文件读取对象
func (ibc *ImagesBedClient) Reader(md5 string) (string, *bufio.Reader) {
	req := httplib.Get(ibc.GetDownloadURL(md5))
	resp, err := req.DoRequest()
	if err != nil {
		return "", nil
	}

	if cd := resp.Header.Get("Content-Disposition"); cd != "" {
		return strings.ReplaceAll(cd, "attachment; filename=", ""),
			bufio.NewReaderSize(resp.Body, 32*1024)
	}
	return "", bufio.NewReaderSize(resp.Body, 32*1024)
}

// Download 下载文件
func (ibc *ImagesBedClient) Download(md5 string, filepath string, filename ...string) string {
	name, reader := ibc.Reader(md5)
	if reader != nil {
		if len(filename) > 0 {
			name = filename[0]
		}
		file, err := os.Create(filepath + "/" + name)
		if err != nil {
			return ""
		}
		defer func(file *os.File) {
			err := file.Close()
			if err != nil {
				logs.Debug("error")
			}
		}(file)
		writer := bufio.NewWriter(file)
		if writer != nil {
			_, err := io.Copy(writer, reader)
			if err != nil {
				return ""
			} else {
				return filepath + "/" + name
			}
		}
	}
	return ""
}

// Search 搜索文件
func (ibc *ImagesBedClient) Search(keyword string) ([]*ImageInfo, error) {
	req := httplib.Get(ibc.BuildURL("search/" + keyword))
	if resp, err := req.DoRequest(); err == nil {
		if resp.StatusCode == http.StatusOK {
			images := make([]*ImageInfo, 0)
			bytes, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return nil, err
			}

			err1 := json.Unmarshal(bytes, &images)
			if err1 != nil {
				return nil, err1
			}
			return images, nil
		} else {
			return nil, errors.New("net error")
		}
	} else {
		return nil, err
	}
}
